package net.sharpf2.api.interfaces;

import java.util.ArrayList;
import net.sharpf2.sfcore.client.Interface;
import net.sharpf2.api.content.WorldObject;
import net.sharpf2.api.game.Interfaces;
import net.sharpf2.api.world.Objects;
import net.sharpf2.api.types.Content;
import net.sharpf2.api.info.Item;
import net.sharpf2.api.Methods;
import net.sharpf2.api.Globals;
import net.sharpf2.api.util.Mathematics;

/**
 * @author Drew Lindsey
 * @author Piotr Gajdowski
 * @author Matty Cov
 */
public class Bank {

    /**
     * Return the actual bank interface
     * @return The bank interface
     */
    public static Content<Interface> getInterface() {
        return Interfaces.get(Constants.BANK_INTERFACE, 0);
    }

    /**
     * Gets the deposit box class
     * @return DepositBox
     */
    public static DepositBox getDepositBox() {
        return new DepositBox();
    }

    /**
     * Returns all items in the inventory
     * @return items
     */
    public static Item[] getItems() {
        ArrayList<Item> items = new ArrayList<Item>();
        Interface[] itemComponents = Interfaces.get(Constants.BANK_INTERFACE, Constants.COMPONENT_INVENTORY).getContent().getChildren();
        for (Interface child : itemComponents) {
            if (child != null && child.getId() > 0) {
                items.add(new Item(new Content<Interface>(child)));
            }
        }
        return items.toArray(new Item[items.size()]);
    }

    /**
     * Gets the item in the bank
     * @param   ids id for the Item
     * @return  The first item with the matching id.
     */
    public static Item getItem(int... ids) {
        for (Item i : getItems()) {
            for (int id : ids) {
                if (i.getId() == id) {
                    return i;
                }
            }
        }
        return null;
    }

    /**
     * Withdraws All of an item
     * @param id  ID of the item to withdraw
     */
    public static void withdrawAll(int... id) {
        Item item = getItem(id);
        if (item != null) {
            item.interact("(Withdraw-All|Alle entnehmen|Retirer tout)");
        }
    }

    /**
     * Withdraws the specified amount of an item with the specified id
     * @param id        ID of the item wanting to withdraw
     * @param amount    Amount of the item wanted to withdraw
     */
    public static void withdraw(int id, int amount) {
        Item item = getItem(id);
        if (item != null) {
            for (String it : item.getContent().getActions()) {
                if (it.contains("(Withdraw-" + amount + "|" + amount + " entnehmen|Retirer " + amount + ")")) {
                    item.interact("(Withdraw-" + amount + "|" + amount + " entnehmen|Retirer " + amount + ")");
                } else {
                    item.interact("(Withdraw-X|X entnehmen|Retirer X)");
                    Methods.sleep(500); // needs randomized
                    Globals.CONTROLLER.getKeyboard().sendKeys(String.valueOf(amount), true);
                }
            }
        }
    }

    /**
     * Deposits all in the inventory using button
     */
    public static void depositAllInventory() {
        Interfaces.get(Constants.BANK_INTERFACE, Constants.BUTTON_DEPOSIT_INVENTORY).getActions().click();
    }

    /**
     * Gets the current open bank tablad.
     * @return Opened tab (1-9)
     */
    public static int currentBankTab() {
        int tabs = Globals.CLIENT.getSettings().getData()[1248];
        if (tabs < -1900000000 && tabs > -2100000000) {
            return 1;
        }
        if (tabs < -1800000000 && tabs > -2000000000) {
            return 2;
        }
        if (tabs < -1700000000 && tabs > -1800000000) {
            return 3;
        }
        if (tabs < -1600000000 && tabs > -1700000000) {
            return 4;
        }
        if (tabs < -1400000000 && tabs > -1500000000) {
            return 5;
        }
        if (tabs < -1300000000 && tabs > -1400000000) {
            return 6;
        }
        if (tabs < -1200000000 && tabs > -1300000000) {
            return 7;
        }
        if (tabs < -1000000000 && tabs > -1100000000) {
            return 8;
        }
        if (tabs < -900000000 && tabs > -1000000000) {
            return 9;
        }
        return 1;
    }

    /**
     * Deposits all worn items using button
     */
    public static void depositAllWorn() {
        Interfaces.get(Constants.BANK_INTERFACE, Constants.BUTTON_DEPOSIT_WORN).getActions().click();
    }

    /**
     * Deposits all in the beast of burden using button
     */
    public static void depositAllBeast() {
        Interfaces.get(Constants.BANK_INTERFACE, Constants.BUTTON_DEPOSIT_BEAST).getActions().click();
    }

    /**
     * Deposits all items except the ones with the specified id
     * @param ids   IDs of items to keep
     */
    public static void depositAllExcept(int... ids) {
        for (int i = 0; i < Inventory.getItemCount(); i++) {
            if (i > Inventory.getItemCount()) {
                break;
            }
            boolean keepItem = false;
            Item item = Inventory.getItems()[i];
            for (int id : ids) {
                if (item.getId() == id) {
                    keepItem = true;
                }
            }
            if (!keepItem) {
                if (Inventory.getCount(item.getId(), true) > 1) {
                    item.interact("(Deposit-All|Alle deponieren|Déposer tout)");
                    Methods.sleep(Mathematics.random(500, 700));
                } else {
                    item.interact("(Deposit|Deponieren|Déposer)");
                }
            }
        }
    }

    /**
     * Closes the bank interface
     */
    public static void close() {
        Interfaces.get(Constants.BANK_INTERFACE, Constants.BUTTON_CLOSE).getActions().click();
    }

    /**
     * Get's the nearest bank booth, and opens the bank interface.
     */
    public static void open() {
        Content<WorldObject> object = Objects.getNearest(Constants.BANK_BOOTHS);
        if (object != null) {
            while (!isOpen() && !Thread.currentThread().isInterrupted()) {
                Objects.getNearest(Constants.BANK_BOOTHS).getActions().click("(Use-quickly|Schnellzugriff|Accès rapide)");
                Methods.sleep(1000);
            }
        }
    }

    /**
     * Checks if the bank interface is open
     * @return  true if the bank interface is open, else false
     */
    public static boolean isOpen() {
        return Interfaces.isInterfaceValid(Constants.BANK_INTERFACE);
    }

    /**
     * @author Cov
     */
    public static class DepositBox {

        /**
         * Returns the actual deposit box interface.
         * @return The deposit box interface
         */
        public Content<Interface> getInterface() {
            return Interfaces.get(Constants.DEPOSIT_BOX, 0);
        }

        /**
         * Checks if the deposit box interface is open or not.
         * @return true if is opened, otherwise false.
         */
        public boolean isOpen() {
            return Interfaces.isInterfaceValid(Constants.DEPOSIT_BOX);
        }

        /**
         * Gets all the items in the deposit box window.
         * @return Items array.
         */
        private Item[] getItems() {
            if (isOpen()) {
                ArrayList<Item> items = new ArrayList<Item>();
                Interface[] itemComponents = Interfaces.get(Constants.DEPOSIT_BOX, Constants.DEPOSIT_INVENTORY_ITEMS).getContent().getChildren();
                for (Interface child : itemComponents) {
                    if (child != null && child.getId() > 0) {
                        items.add(new Item(new Content<Interface>(child)));
                    }
                }
                return items.toArray(new Item[items.size()]);
            }
            return null;
        }

        /**
         * Gets a specified item.
         * @param   id  item ID
         * @return  If Item is not null, return Item, otherwise return null.
         */
        public Item getItem(int id) {
            for (Item i : getItems()) {
                if (i.getId() == id) {
                    return i;
                }
            }
            return null;
        }

        /**
         * Deposits every item except given item ID's.
         * @param ids   Items which do not need to be banked.
         */
        public void depositAllExcept(int... ids) {
            if (isOpen()) {
                for (Item item : getItems()) {
                    boolean skip = false;
                    for (int i : ids) {
                        if (item.getId() == i) {
                            skip = true;
                        }
                    }
                    if (!skip && item.getId() != -1) {
                        item.interact("(Deposit-All|Alle deponieren|Déposer tout)");
                    }
                }
            }
        }

        /**
         * Deposits all items from inventory.
         */
        public void depositAllInventory() {
            if (isOpen()) {
                Interfaces.get(Constants.BANK_INTERFACE, Constants.DEPOSIT_BUTTON_INVENTORY).getActions().click();
            }
        }

        /**
         * Deposits all equipped items.
         */
        public void depositAllWorn() {
            if (isOpen()) {
                Interfaces.get(Constants.BANK_INTERFACE, Constants.DEPOSIT_BUTTON_WORN).getActions().click();
            }
        }

        /**
         * Deposits all items from beast of burden.
         */
        public void depositAllBeast() {
            if (isOpen()) {
                Interfaces.get(Constants.BANK_INTERFACE, Constants.DEPOSIT_BUTTON_BEAST).getActions().click();
            }
        }

        /**
         * Closes the deposit box interface.
         */
        public void close() {
            if (isOpen()) {
                Interfaces.get(Constants.BANK_INTERFACE, Constants.DEPOSIT_BUTTON_CLOSE).getActions().click();
            }
        }

        /**
         * Get's the nearest deposit box, and opens it.
         */
        public void open() {
            Content<WorldObject> object = Objects.getNearest(Constants.DEPOSIT_BOXES);
            if (object != null) {
                while (!isOpen() && !Thread.currentThread().isInterrupted()) {
                    Objects.getNearest(Constants.DEPOSIT_BOXES).getActions().click("(Deposit|Deponieren|Déposer)");
                    Methods.sleep(1000);
                }
            }
        }
    }

    /**
     * 
     * @author Matty Cov
     *
     */
    public static class EquipScreen {

        /**
         * 
         * @return Equipment stats Interface
         */
        public static Content<Interface> getInterface() {
            return Interfaces.get(Constants.EQUIP_INTERFACE, 0);
        }

        /**
         * 
         * @return Array of Items of your worn equipment
         */
        public static Item[] getEquipment() {
            if (isOpen()) {
                ArrayList<Item> items = new ArrayList<Item>();
                for (int i = 0; i < Constants.EQUIP_BOX_CHILDREN.length; i++) {
                    Interface inter = Interfaces.getChild(Constants.EQUIP_INTERFACE, Constants.EQUIP_BOX, Constants.EQUIP_BOX_CHILDREN[i]).getContent();
                    if (inter != null && inter.getId() > 0) {
                        items.add(new Item(new Content<Interface>(inter)));
                    }
                }
                return items.toArray(new Item[items.size()]);
            }
            return null;
        }

        /**
         * @param   id ID of the Item
         * @return  the item with the corresponding ID else null
         */
        public static Item getItem(int id) {
            for (Item i : getEquipment()) {
                if (i.getId() == id) {
                    return i;
                }
            }
            return null;
        }

        /**
         * @return True if the equipment is open, otherwise false.
         */
        public static boolean isOpen() {
            return Interfaces.isInterfaceValid(Constants.EQUIP_INTERFACE);
        }

        /**
         * @param item      Item to interact with
         * @param action    String of the action you want to do
         */
        public static void interact(Item item, String action) {
            item.interact(action);
        }

        /**
         * Closes Equipment interface
         */
        public static void close() {
            Content<Interface> close = Interfaces.get(Constants.EQUIP_BOX, Constants.EQUIP_CLOSE);
            close.getActions().click();
        }

        /**
         * Switches to bank interface
         */
        public static void switchToBank() {
            Content<Interface> swich = Interfaces.get(Constants.EQUIP_BOX, Constants.EQUIP_SHOW_BANK);
            swich.getActions().click();
        }
    }

    public static class Constants {
        //Bank

        public static final int BANK_INTERFACE = 762;
        public static final int BUTTON_CLOSE = 43;
        public static final int BUTTON_DEPOSIT_BEAST = 38;
        public static final int BUTTON_DEPOSIT_INVENTORY = 34;
        public static final int BUTTON_DEPOSIT_WORN = 36;
        public static final int BUTTON_HELP = 44;
        public static final int BUTTON_INSERT = 15;
        public static final int BUTTON_ITEM = 19;
        public static final int BUTTON_NOTE = 19;
        public static final int BUTTON_SEARCH = 17;
        public static final int BUTTON_SWAP = 15;
        public static final int BUTTON_EQUIPMENT = 117;
        public static final int COMPONENT_INVENTORY = 93;
        public static final int TEXT_F2P_ITEM_COUNT = 29;
        public static final int TEXT_F2P_ITEM_MAX = 30;
        public static final int TEXT_P2P_ITEM_COUNT = 31;
        public static final int TEXT_P2P_ITEM_MAX = 32;
        public static final int SCROLL_BAR = 114;
        public static final int COMPONENT_SEARCH = 752;
        public static final int COMPONENT_SEARCH_INPUT = 5;
        public static final int WIDGET_EQUIP = 667;
        public static final int COMPONENT_EQUIP_INVENTORY = 7;
        public static final int WIDGET_COLLECTION_BOX = 105;
        public static final int BUTTON_COLLECTION_BOX_CLOSE = 13;
        public static final int[] COMPONENT_BANK_TABS = {63, 61, 59, 57, 55, 53, 51, 49, 47};
        public static final int[] COMPONENT_BANK_FIRST_ITEMS = {78, 79, 80, 81, 82, 83, 84, 85, 86};
        public static final int[] BANK_BOOTHS = {782, 2012, 2015, 2213, 4483, 6084, 11402, 11758, 12759, 14367, 19230, 24914, 25808, 26972, 27663, 29085, 34752, 35647, 36786};
        //Deposit Box
        public static final int[] DEPOSIT_BOXES = {2045, 9398, 20228, 24995, 25937, 26969, 32924, 32930, 32931, 34755, 36788, 39830, 45079};
        public static final int DEPOSIT_BOX = 11;
        public static final int DEPOSIT_BUTTON_CLOSE = 15;
        public static final int DEPOSIT_BUTTON_INVENTORY = 18;
        public static final int DEPOSIT_BUTTON_WORN = 20;
        public static final int DEPOSIT_BUTTON_BEAST = 22;
        public static final int DEPOSIT_INVENTORY_ITEMS = 17;
        //Equipment Screen
        public static final int EQUIP_INTERFACE = 667;
        public static final int EQUIP_BOX = 7;
        public static final int EQUIP_HEAD = 0;
        public static final int EQUIP_NECK = 1;
        public static final int EQUIP_WEAPON = 2;
        public static final int[] EQUIP_BOX_CHILDREN = {0, //Head
            1, //Cape
            2, //Neck
            3, //Weapon
            4, //Chest
            5, //Off-hand
            7, //Legs
            9, //Gloves
            10, //Feet
            12, //Ring
            13}; //Ammo
        public static final int EQUIP_SHOW_BANK = 48;
        public static final int EQUIP_CLOSE = 74;
    }
}
